#include <bits/stdc++.h>
using namespace std;

int n, m;
int sum; // 记录MST的最终权值总和

// 连通图中的任意两个节点的权值weight[i][j]
int weight[5001][5001];

// 记录距离MST最短的权值
int lowcost[5001];

void Prim()
{
    // 以第1个节点为MST的初始状态，并以此初始化最小权值数组
    for(int i=1; i<=n; i++)
        lowcost[i] = weight[1][i];

    // 将节点1标记为0，表达节点1已经进入MST
    lowcost[1] = 0;

    // 不断地将剩余的节点拉入MST中
    int i, j;
    int min;     // 记录当前MST与剩余节点集合中，所有边的最小权值
    int minIndex;// 记录连接MST与剩余节点集合的最小权值的边的节点
    for(i=1; i<n; i++)
    {
        min = INT_MAX;

        // 在已有的MST与剩余节点集合的所有边中
        // 得到权值最小的边，以及这条边在剩余节点集合中的那个点的序号
        for(j=1; j<=n; j++)
        {
            if(lowcost[j]!=0 && lowcost[j]<min)
            {
                min = lowcost[j];
                minIndex = j;
            }
        }

        // 将第minIndex个节点，拉入MST阵营中
        lowcost[minIndex] = 0;
        sum += min;

        // 将第minIndex个点的所关联的权值，更新到lowcost数组中
        for(j=1; j<=n; j++)
        {
            if(weight[minIndex][j] < lowcost[j])
                lowcost[j] = weight[minIndex][j];
        }
    }

    // 检测一遍lowcost，如果发现有非0值代表原本的图是非连通图
    for(i=1; i<=n; i++)
    {
        if(lowcost[i] != 0)
        {
            cout << "orz" << endl;
            return;
        }
    }

    // 输出最终答案
    cout << sum << endl;
}

int main(int argc, char const *argv[])
{
    // 输入n个节点，m条边
    cin >> n >> m;

    // 初始化weight均为INT_MAX，代表没有边
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<=n; j++)
            weight[i][j] = INT_MAX;
    }

    // 输入每一条边
    int u, v, w; // 每条边的端点和权值(u, v)w
    for(int i=1; i<=m; i++)
    {
        cin >> u >> v >> w;

        // 只记录题目给定的(u,v)的最小权值
        if(w < weight[u][v])
            weight[u][v] = weight[v][u] = w;
    }
    
    // 普利姆算法
    Prim();

    return 0;
}
